import requests
import json
from datetime import datetime
from distutils.util import strtobool
from sqlalchemy.orm import Session
from core.response import resp_500
from core.logger import logger
from common.notice_tools import NoticeTools
from app.fault_self_recovery.models.fsr_rabbitmq_queue import FSRRabbitmqQueue
from app.notice_center.models.nc_n9e_alarm_record import NCN9eAlarmRecord
from app.notice_center.handlers.nc_n9e_alarm_handler import NCN9eAlarmHandler

from common.welab_k8s import init_k8s
from common.welab_k8s.k8s_deployment import K8sDeployment
from common.welab_k8s.k8s_statefulset import K8sStatefulset
from setting import config


class NCN9eCallbackRabbitmqQueueHandler():
    """  Self Healing Handler
    """
    def __init__(self):
        init_k8s()
        self.handle_url = config.FSR_RABBITMQ_QUEUE_URL
        self.token = config.FSR_RABBITMQ_QUEUE_TOKEN
        self.k8s_deployment = K8sDeployment()
        self.k8s_statefulset = K8sStatefulset()
        self.notice_tools = NoticeTools()



    def filter_alarm_info(self, data: dict):
        alarm_data = {
            "status": "resolved" if data["is_recovered"] else "firing",
            "service": "",
            "vhost": "",
            "queue": ""
        }
        
        for tag in data["tags"]:
            if tag.startswith("service="):
                alarm_data["service"] = tag.split("service=")[1]
                
            if tag.startswith("vhost="):
                alarm_data["vhost"] = tag.split("vhost=")[1]
                
            if tag.startswith("queue="):
                alarm_data["queue"] = tag.split("queue=")[1]
                
        return alarm_data
        



    def post_nc_n9e_heal_rabbitmq_queue(self, db: Session, data: dict, token: str):
        """
        rabbitmq队列消息祖塞
        """
        try:
            logger.info(f"rabbitmq queue 收到回调告警信息=>{data}")
            
            alarm_data = self.filter_alarm_info(data)
            
            # 前期数据判断
            if "" in list(alarm_data.values()):
                # token验证
                logger.error(f"rabbitmq queue: value is null")
                return False
            
            if alarm_data["service"] not in ["mq-service"]:
                # 现在就只有一个mq集群的回调
                logger.error(f"rabbitmq queue: service is not mq-service")
                return False

            if self.token != token:
                # token验证
                logger.error(f"rabbitmq queue: token is error")
                return False

            # 全局维护：不告警、不回调
            nc_n9e_alarm_handler = NCN9eAlarmHandler()
            global_record_info = NCN9eAlarmRecord.get_object_info_for_block_global(db)
            if global_record_info and not nc_n9e_alarm_handler.check_alert_notice_maintain(global_record_info):
                logger.info(f"container cpu usage: block alarm in global maintain")
                return True

            rabbitmq_queue_object = FSRRabbitmqQueue.get_object_by_cluster_vhost_name(db, alarm_data['service'], alarm_data['vhost'], alarm_data['queue'])
            if not rabbitmq_queue_object:
                # 如果不存在，不处理
                logger.warning(f"rabbitmq queue:{alarm_data['queue']} not in database, no handle")
                return True

            rabbitmq_queue_info = FSRRabbitmqQueue.get_object_info_by_uuid(db, rabbitmq_queue_object.uuid)
            if not strtobool(str(rabbitmq_queue_info["state"])):
                # 如果已关闭动态扩缩容，不处理
                logger.warning(f"rabbitmq queue:{alarm_data['queue']} is disable, no handle")
                return True

            if rabbitmq_queue_info["status"] == "firing" and alarm_data["status"] == "firing":
                # 如果重复告警，不处理
                logger.warning(f"rabbitmq queue:{alarm_data['queue']} is firing, no handle")
                return True

            if not self.check_consumer(rabbitmq_queue_info, alarm_data):
                # 检查服务信息
                logger.warning(f"check consumer failed")
                return True

            # 处理rabbitmq队列消息祖塞
            result = self.task_rabbitmq_queue(db, alarm_data, rabbitmq_queue_info)
            if not result:
                logger.error(f"handle rabbitmq queue failed")
                return False

            logger.info(f"handle rabbitmq queue success")
        except Exception as e:
            message = f"handle rabbitmq queue error"
            logger.exception(f"{message} => {e}")
            return resp_500(message)

        return True


    def check_consumer(self, rabbitmq_queue_info:dict, alarm_data: dict):
        if alarm_data["status"] == "resolved":
            logger.info(f"{alarm_data['status']} not check consumer number")
            return True

        if rabbitmq_queue_info["classes"] == "deployment":
            server_info = self.k8s_deployment.read_namespaced_deployment(rabbitmq_queue_info["consumer"], "prod")
        elif rabbitmq_queue_info["classes"] == "statefulset":
            server_info = self.k8s_statefulset.read_namespaced_statefulset(rabbitmq_queue_info["consumer"], "prod")
        else:
            logger.error(f"queue consumer:{rabbitmq_queue_info['consumer']} not deployment or statefulset, no handle")
            return False

        # 配置的最大值比现在的还小，则不扩容
        if server_info["replicas"] >= rabbitmq_queue_info['max']:
            logger.error(f"{rabbitmq_queue_info['consumer']}:{server_info['replicas']} >= {rabbitmq_queue_info['max']}, no handle")
            return False

        # 记录扩容前的节点数
        rabbitmq_queue_info['number'] = server_info["replicas"]

        return True



    def handle_rabbitmq_queue(self, alarm_data: dict, server_data: dict):
        headers = {
            "Content-Type": "application/json",
        }
        data = {
            "status": alarm_data["status"],
            "application": server_data["consumer"],
            "namespace": "prod",
            "classes": server_data["classes"],
            "number": server_data["number"],
            "max": server_data["max"]
        }
        explain = {
            "firing": "扩容",
            "resolved": "缩容"
        }

        try:
            # 回调扩缩容接口
            req = requests.post(url=self.handle_url, headers=headers, data=json.dumps(data), timeout=5)
            if req.status_code != 200:
                message = f"n9e故障自愈 => 队列:{server_data['name']} 消费者服务:{data['application']} 队列阻塞回调 {explain[alarm_data['status']]} 失败"
                logger.error(message)
            else:
                message = f"n9e故障自愈 => 队列:{server_data['name']} 消费者服务:{data['application']} 队列阻塞回调 {explain[alarm_data['status']]} 成功"
                logger.info(message)
        except Exception as e:
            message = f"n9e故障自愈 => 队列:{server_data['name']} 消费者服务:{data['application']} 队列阻塞回调 {explain[alarm_data['status']]} 异常"
            logger.exception(f"{message} error: {e}")

        # 发送处理结果信息到企业微信群
        self.notice_tools.send_wechat_group(message)

        return message



    def task_rabbitmq_queue(self, db: Session, alarm_data: dict, server_data: dict):
        """
        处理rabbitmq队列消息祖塞
        """

        # 处理动态扩缩容
        if alarm_data["status"] == "firing":
            message = self.handle_rabbitmq_queue(alarm_data, server_data)
            server_data["handle"] = True
        elif alarm_data["status"] == "resolved" and strtobool(str(server_data["handle"])):
            message = self.handle_rabbitmq_queue(alarm_data, server_data)
            server_data["handle"] = False
        else:
            message = "故障自愈 => 无处理"
            server_data["handle"] = False


        # 更新动态扩缩容服务状态
        server_data["status"] = alarm_data["status"]
        result = FSRRabbitmqQueue.update(db, server_data)
        if not result:
            logger.error(f"update rabbitmq queue to database failed")
            return False
        return True




